package com.yj.auto.utils;

import java.util.List;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;

import com.jfinal.log.Log;
import com.yj.auto.Constants;

/**
 * @Description: 定时任务管理类
 * 
 */
public class QuartzUtil {
	private static final Log logger = Log.getLog(QuartzUtil.class);
	// public final static String JOB_STATE_UNKNOWN = "UNKNOWN";
	public final static String JOB_STATE_NONE = "NONE";
	public final static String JOB_STATE_DISABLE = "DISABLE";
	public final static String DEFAULT_JOB_GROUP = "DEFAULT_JOB_GROUP";
	public final static String DEFAULT_TRIGGER_GROUP = "DEFAULT_TRIGGER_GROUP";

	public static QuartzUtil utils = null;
	private SchedulerFactory schedulerFactory = null;

	private QuartzUtil() {
		String conf = ClassUtil.getPathByClassPath(Constants.CONF_QUARTZ);
		try {
			schedulerFactory = new StdSchedulerFactory(conf);
		} catch (SchedulerException e) {
			logger.error("定时任务初始化失败!", e);
		}
	}

	public static QuartzUtil me() {
		if (null == utils) {
			utils = new QuartzUtil();
		}
		return utils;
	}

	/**
	 * 获取触发器key
	 */
	public static TriggerKey getTriggerKey(String triggerName, String triggerGroup) {
		return TriggerKey.triggerKey(triggerName, triggerGroup);
	}

	public static TriggerKey getTriggerKey(String triggerName) {
		return getTriggerKey(triggerName, DEFAULT_TRIGGER_GROUP);
	}

	/**
	 * 获取jobKey
	 */
	public static JobKey getJobKey(String jobName, String jobGroup) {
		return JobKey.jobKey(jobName, jobGroup);
	}

	public static JobKey getJobKey(String jobName) {
		return getJobKey(jobName, DEFAULT_JOB_GROUP);
	}

	/**
	 * @Description: 添加一个定时任务，使用默认的任务组名，触发器名，触发器组名
	 * 
	 * @param jobName
	 *            任务名
	 * @param jobClass
	 *            任务
	 * @param time
	 *            时间设置，参考quartz说明文档
	 */
	@SuppressWarnings("unchecked")
	public void addJob(String jobName, Class jobClass, String time) {
		this.addJob(jobName, DEFAULT_JOB_GROUP, jobName, DEFAULT_TRIGGER_GROUP, jobClass, time);
	}

	/**
	 * @Description: 添加一个定时任务
	 * 
	 * @param jobName
	 *            任务名
	 * @param jobGroupName
	 *            任务组名
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 * @param jobClass
	 *            任务
	 * @param time
	 *            时间设置，参考quartz说明文档
	 */
	@SuppressWarnings("unchecked")
	public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String time) {
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build(); // 任务名，任务组，任务执行类
			// 触发器
			CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(time); // 触发器时间设定
			CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName).withSchedule(schedBuilder).build();// 触发器名,触发器组
			sched.scheduleJob(jobDetail, trigger);
		} catch (Exception e) {
			logger.error("添加定时任务[" + jobGroupName + "." + jobName + "],CORN[" + time + "]失败", e);
		}
	}

	/**
	 * @Description: 修改一个任务的触发时间(使用默认的任务组名，触发器名，触发器组名)
	 * 
	 * @param jobName
	 * @param time
	 */
	@SuppressWarnings("unchecked")
	public void modifyJobTime(String jobName, String time) {
		this.modifyJobTime(jobName, DEFAULT_TRIGGER_GROUP, time);
	}

	public void modifyJobTime(String jobName, String jobGroup, String time) {
		JobKey jobKey = getJobKey(jobName, jobGroup);
		try {
			if (existsJob(jobKey)) {
				Scheduler sched = schedulerFactory.getScheduler();
				List<? extends Trigger> list = sched.getTriggersOfJob(jobKey);
				for (Trigger t : list) {
					TriggerKey triggerKey = t.getKey();
					modifyTriggerTime(triggerKey, time);
				}
			}
		} catch (Exception e) {
			logger.error("修改定时任务[" + jobKey + "],CORN[" + time + "]失败", e);
		}
	}

	/**
	 * @Description: 修改一个任务的触发时间
	 * 
	 * @param triggerName
	 * @param triggerGroup
	 * @param time
	 * 
	 */
	public void modifyTriggerTime(String triggerName, String triggerGroup, String time) {
		TriggerKey triggerKey = getTriggerKey(triggerName, triggerGroup);
		modifyTriggerTime(triggerKey, time);
	}

	public void modifyTriggerTime(TriggerKey triggerKey, String time) {
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
			if (trigger == null) {
				return;
			}
			String oldTime = trigger.getCronExpression();
			if (!oldTime.equalsIgnoreCase(time)) {
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time).withMisfireHandlingInstructionDoNothing();
				trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
				sched.rescheduleJob(triggerKey, trigger);// 重启触发器
			}
		} catch (Exception e) {
			logger.error("修改定时任务[" + triggerKey + "],CORN[" + time + "]失败", e);
		}
	}

	/**
	 * @Description: 移除一个任务(使用默认的任务组名，触发器名，触发器组名)
	 * 
	 * @param jobName
	 * 
	 */
	public void removeJob(String jobName) {
		this.removeJob(jobName, DEFAULT_JOB_GROUP);
	}

	/**
	 * @Description: 移除一个任务
	 * 
	 * @param jobName
	 * @param jobGroup
	 */
	public void removeJob(String jobName, String jobGroup) {
		JobKey jobKey = getJobKey(jobName, jobGroup);
		try {
			if (existsJob(jobKey)) {
				Scheduler sched = schedulerFactory.getScheduler();
				List<? extends Trigger> list = sched.getTriggersOfJob(jobKey);
				for (Trigger t : list) {
					TriggerKey triggerKey = t.getKey();
					sched.pauseTrigger(triggerKey);// 停止触发器
					sched.unscheduleJob(triggerKey);// 移除触发器
				}
				sched.deleteJob(jobKey);// 删除任务
			}
		} catch (Exception e) {
			logger.error("删除定时任务[" + jobKey + "]调度器失败", e);
		}
	}

	/**
	 * @Description: 移除一个任务
	 * 
	 * @param triggerName
	 * @param triggerGroup
	 */
	public void removeTrigger(String triggerName, String triggerGroup) {
		TriggerKey triggerKey = getTriggerKey(triggerName, triggerGroup);
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			if (existsTrigger(triggerKey)) {
				sched.pauseTrigger(triggerKey);// 停止触发器
				sched.unscheduleJob(triggerKey);// 移除触发器
			}
		} catch (Exception e) {
			logger.error("删除定时任务[" + triggerKey + "]调度器失败", e);
		}
	}

	/**
	 * @Description:启动所有定时任务
	 */
	public void startJobs() {
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			sched.start();
		} catch (Exception e) {
			logger.error("启动定时任务调度器失败", e);
		}
	}

	public void startJob(String jobName, String jobGroup) {
		JobKey jobKey = getJobKey(jobName, jobGroup);
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			if (existsJob(jobKey)) {
				sched.triggerJob(jobKey);
			}
		} catch (Exception e) {
			logger.error("启动定时任务[" + jobKey + "]失败", e);
		}
	}

	public void startJob(String jobName) {
		startJob(jobName, DEFAULT_JOB_GROUP);
	}

	/**
	 * @Description:关闭所有定时任务
	 */
	public void shutdownJobs() {
		try {
			Scheduler scheduler = schedulerFactory.getScheduler();
			if (!scheduler.isShutdown()) {
				scheduler.shutdown();
			}
		} catch (Exception e) {
			logger.error("关闭定时任务调度器失败", e);
		}
	}

	/**
	 * @Description:挂起所有定时任务
	 */
	public void pauseJobs() {
		try {// 先暂停任务调度器
			Scheduler scheduler = schedulerFactory.getScheduler();
			if (!scheduler.isInStandbyMode()) {
				scheduler.standby();// pause the scheduler
				logger.debug("暂停任务调度器");
			}
		} catch (Exception e) {
			logger.error("挂起定时任务调度失败", e);
		}
	}

	public void pauseJob(String jobName, String jobGroup) {
		JobKey jobKey = getJobKey(jobName, jobGroup);
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			if (existsJob(jobKey)) {
				sched.pauseJob(jobKey);
			}
		} catch (Exception e) {
			logger.error("挂起定时任务[" + jobKey + "]失败", e);
		}
	}

	public void pauseJob(String jobName) {
		pauseJob(jobName, DEFAULT_JOB_GROUP);
	}

	/**
	 * @Description: 恢复所有定时任务
	 */
	public void resumeJobs() {
		try {
			Scheduler scheduler = schedulerFactory.getScheduler();
			if (scheduler.isInStandbyMode()) {
				scheduler.resumeAll();// start the scheduler
			}
		} catch (Exception e) {
			logger.error("恢复任务调度器失败", e);
		}
	}

	public void resumeJob(String jobName, String jobGroup) {
		JobKey jobKey = getJobKey(jobName, jobGroup);
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			if (existsJob(jobKey)) {
				sched.resumeJob(jobKey);
			}
		} catch (Exception e) {
			logger.error("启动定时任务[" + jobKey + "]失败", e);
		}
	}

	public void resumeJob(String jobName) {
		resumeJob(jobName, DEFAULT_JOB_GROUP);
	}

	public String jobState(String triggerName, String triggerGroup) {
		TriggerKey triggerKey = getTriggerKey(triggerName, triggerGroup);
		String s = JOB_STATE_NONE;
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			if (existsTrigger(triggerKey)) {
				TriggerState state = sched.getTriggerState(triggerKey);
				s = state.name();
			}
		} catch (Exception e) {
			logger.error("获取定时任务[" + triggerKey + "]状态失败", e);
		}
		return s;
	}

	public String jobState(String triggerName) {
		return jobState(triggerName, DEFAULT_TRIGGER_GROUP);
	}

	public boolean existsJob(String jobName, String jobGroup) {
		JobKey jobKey = getJobKey(jobName, jobGroup);
		return existsJob(jobKey);
	}

	public boolean existsJob(JobKey jobKey) {
		boolean exists = false;
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			JobDetail job = sched.getJobDetail(jobKey);
			exists = null != job;
		} catch (Exception e) {
			logger.error("获取定时任务[" + jobKey + "]失败", e);
		}
		return exists;
	}

	public boolean existsTrigger(TriggerKey triggerKey) {
		boolean exists = false;
		try {
			Trigger trigger = getTrigger(triggerKey);
			exists = null != trigger;
		} catch (Exception e) {
			logger.error("获取定时任务调度器[" + triggerKey + "]失败", e);
		}
		return exists;
	}

	public Trigger getTrigger(TriggerKey triggerKey) {
		Trigger trigger = null;
		try {
			Scheduler sched = schedulerFactory.getScheduler();
			trigger = sched.getTrigger(triggerKey);
		} catch (Exception e) {
			logger.error("获取定时任务调度器[" + triggerKey + "]失败", e);
		}
		return trigger;
	}
}